package com.ftg.learn.back.pattern.factory.reflech;


import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * java.lang. Class : 代表类接口等
 * java.lang.reflect.Field  Field :  Class反射对像对应运行中的类、接口里面的属性
 *  getAnnotation() 用来判断，field上面是某用指定的注解进行修饰
 * java.lang.reflect.Method Method : 代表class反射对象里面的方法
 * java.beans.PropertyDescriptor PropertyDescriptor : 代表的是一个field的对应的setter 以及getter
 *   getWriteMethod() 获得write setter
 *   getReadMethod() 获得read   getter
 *
 * @author kangjx
 * @createTime 2022/9/1
 */
public class LeranReflech<T> {


    /**
     * 我们约定了，一个类的全局变量 ，为了保存可以实现依赖倒置 construct setter getter
     * @param c     T 的一个Class 类的实例
     * @return     T 的实例s
     */
    public T createPerson(Class<T> c,Object...o){
        T t1 = null;
        try {
            t1 = c.newInstance();

            Field[] fs = c.getDeclaredFields();
            for (int i = 0; i < fs.length; i++) {
                System.out.println(fs[i].getName() +":所有的字段名称 getDeclaredFields");
                System.out.println(fs[i].getGenericType().getTypeName() +":属性的类型");
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(fs[i].getName(),c);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(t1,o[i]);
            }
        } catch (InstantiationException | IllegalAccessException |  InvocationTargetException | IntrospectionException e) {
            e.printStackTrace();
        }
        return t1;
    }

    /**
     * 我想用这个方法 直接初始化一个类！
     * @param c
     * @return
     */
    public T createPerson(Class<T> c){
        T t1 = null;
        try {
            t1 = c.newInstance();

            Field[] fs = c.getDeclaredFields();
            for (int i = 0; i < fs.length; i++) {
                Field temp = fs[i];
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(temp.getName(),c);
                Method writeMethod = propertyDescriptor.getWriteMethod();

                DefaultVal val = temp.getAnnotation(DefaultVal.class);
                if(val != null){
                    if(fs[i].getGenericType().getTypeName().contains("Integer")){
                        writeMethod.invoke(t1,new Integer(val.value()));
                    }else{
                        writeMethod.invoke(t1,val.value());
                    }
                }
            }
        } catch (InstantiationException | IllegalAccessException | IntrospectionException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return t1;
    }

//    public T createPerson(Class<T> c,Object...o){
//        T t1 = null;
//        try {
//            t1 = c.newInstance();
//            //我们是不是确认类里面有哪些属性 T  sno name () 那么有没有setSno  setName
//            //getDeclaredField 拿到c里面snop属性的实例
////            如果我不知道有哪些属性
//            Field[] fs = c.getDeclaredFields();
//            for (int i = 0; i < fs.length; i++) {
//                System.out.println(fs[i].getName() +":所有的字段名称 getDeclaredFields");
//                System.out.println(fs[i].getGenericType().getTypeName() +":属性的类型");
//                //我们要用到生成的setter和setter
////                setSno(sno);
//                String methodName = "set" + fs[i].getName().substring(0,1).toUpperCase(Locale.ROOT) + fs[i].getName().substring(1);
//                System.out.println(methodName);
////                getMethod(方法名称 ，参数的类型)
////                fs[i].getGenericType().getTypeName() 就是类的全路径
////                Class.forName(fs[i].getGenericType().getTypeName()) 通过全路径取到反射
////                method 让这个实例 执行一下
//                Method method = c.getMethod(methodName,Class.forName(fs[i].getGenericType().getTypeName()));
//                System.out.println(method.getName()+":方法名称 ");
//                method.invoke(t1,o[i]);
////                if(fs[i].getName().equals("sno")){
////                    method.invoke(t1,o[i]);
////                }else{
////                    method.invoke(t1,name);
////                }
//
//            }
//
////            明确知道类里面有哪些属性的时候
//            //用来获取明确的属性
////            Field f = c.getDeclaredField("sno");
////            System.out.println(f.getName());
//////            setAccessible() 可以直接访问私有属性
////            f.setAccessible(true);
//////            表示为t1里面的f设值为sno
////            f.set(t1,sno);
//////            get表示取出t1里面f的属性的值
////            System.out.println(f.get(t1) +":取值操作");
////            Field f1 = c.getDeclaredField("sname");
////            f1.setAccessible(true);
////            f1.set(t1, name);
//
//        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | ClassNotFoundException | InvocationTargetException e) {
//            e.printStackTrace();
//        }
//        return t1;
//    }

    public static void main(String[] args) {
        LeranReflech<Person> l = new LeranReflech<>();
        Person p = l.createPerson(Person.class,123,"abc");
        System.out.println(p.getSno());
        System.out.println(p.getSname());

        Person p1 = l.createPerson(Person.class);
        System.out.println(p1.getSno());
        System.out.println(p1.getSname());

    }

//
//
//    public static void main(String[] args) {
////        Person p = new Person();
//        //类的全路径
//        String personPath = "com.ftg.learn.back.pattern.factory.reflech.Person";
////        jdk - > java.lang - Class
////        Class - > 实例表示正在运行的一个类、接口、enum、注解等
//        try {
//            //反射第一种实现方式，通过类的全路径
////            Class c = Class.forName(personPath);
////            Object obj = c.newInstance();
////            Person p1 = (Person) obj;
//            //第二种实现方式 类名
////            Class<Person> c = Person.class;
//
//            //第三种实现方式 实例点
//            Person p = new Person();
//            Class c = p.getClass();
//
//
//
////            通过C 创建一个新的实例 -- > person父类 (Object)
//            Object obj = c.newInstance();
//            Person p1 = (Person) obj;
//            p1.setSname("张三");
//
//            System.out.println(p1.getSname());
//
//
//        } catch (InstantiationException | IllegalAccessException e) {
//            e.printStackTrace();
//        }
//        // class c - > personPath -> 其实是person类的地址
//    }

}
